﻿using Koala.Pro.Common;
using Koala.Pro.Common.Extension;
using Koala.Pro.Core;
using Koala.Pro.Core.Dto;
using Koala.Pro.Core.Models;
using Koala.Pro.Helpers;
using SqlSugar;

namespace Koala.Pro.Services
{
    public class RoleService : MyCrudService<RoleInfo, int, RolePagedDto>, IRoleService, IMyCrudService<RoleInfo, int, RolePagedDto>, ITransientDependency, IDependency
    {
        private IOuService _ouService;

        private IUserService _userService;

        public RoleService(IApiUserSession currentApiUser, IOuService ouService, IUserService userService)
        {
            base.CurrentApiUser = currentApiUser;
            _ouService = ouService;
            _userService = userService;
        }

        public override Task<Dictionary<string, string>> GetColumnNameAlias()
        {
            return Task.FromResult(new Dictionary<string, string>
        {
            { "PID", "父ID" },
            { "HandNo", "角色编码" },
            { "Name", "角色名称" },
            { "Note", "备注" },
            { "SortCode", "排序码" },
            { "Category", "角色分类" },
            { "Company_ID", "所属公司ID" },
            { "CompanyName", "所属公司名称" },
            { "Creator", "创建人" },
            { "Creator_ID", "创建人ID" },
            { "CreateTime", "创建时间" },
            { "Editor", "编辑人" },
            { "Editor_ID", "编辑人ID" },
            { "EditTime", "编辑时间" },
            { "Deleted", "是否已删除" },
            { "Enabled", "有效标志" }
        });
        }

        protected override ISugarQueryable<RoleInfo> CreateFilteredQueryAsync(RolePagedDto input)
        {
            return base.CreateFilteredQueryAsync(input).WhereIF(input.ExcludeId.HasValue, (RoleInfo t) => (int?)t.Id != input.ExcludeId).WhereIF(input.PID.HasValue, (RoleInfo s) => s.PID == input.PID)
                .WhereIF(!input.HandNo.IsNullOrWhiteSpace(), (RoleInfo t) => t.HandNo.Contains(input.HandNo))
                .WhereIF(!input.Name.IsNullOrWhiteSpace(), (RoleInfo t) => t.Name.Contains(input.Name))
                .WhereIF(!input.Note.IsNullOrWhiteSpace(), (RoleInfo t) => t.Note.Contains(input.Note))
                .WhereIF(!input.SortCode.IsNullOrWhiteSpace(), (RoleInfo t) => t.SortCode.Contains(input.SortCode))
                .WhereIF(!input.Category.IsNullOrWhiteSpace(), (RoleInfo t) => t.Category.Contains(input.Category))
                .WhereIF(!input.Company_ID.IsNullOrWhiteSpace(), (RoleInfo t) => t.Company_ID.Equals(input.Company_ID))
                .WhereIF(!input.CompanyName.IsNullOrWhiteSpace(), (RoleInfo t) => t.CompanyName.Contains(input.CompanyName))
                .WhereIF(!input.Creator.IsNullOrWhiteSpace(), (RoleInfo t) => t.Creator.Contains(input.Creator))
                .WhereIF(!input.Creator_ID.IsNullOrWhiteSpace(), (RoleInfo t) => t.Creator_ID.Contains(input.Creator_ID))
                .WhereIF(input.CreateTimeStart.HasValue, (RoleInfo s) => s.CreateTime >= input.CreateTimeStart.Value)
                .WhereIF(input.CreateTimeEnd.HasValue, (RoleInfo s) => s.CreateTime <= input.CreateTimeEnd.Value)
                .WhereIF(!input.Editor.IsNullOrWhiteSpace(), (RoleInfo t) => t.Editor.Contains(input.Editor))
                .WhereIF(!input.Editor_ID.IsNullOrWhiteSpace(), (RoleInfo t) => t.Editor_ID.Contains(input.Editor_ID))
                .WhereIF(input.EditTimeStart.HasValue, (RoleInfo s) => s.EditTime >= input.EditTimeStart.Value)
                .WhereIF(input.EditTimeEnd.HasValue, (RoleInfo s) => s.EditTime <= input.EditTimeEnd.Value)
                .WhereIF(input.Deleted.HasValue, (RoleInfo s) => s.Deleted == input.Deleted)
                .WhereIF(input.Enabled.HasValue, (RoleInfo s) => s.Enabled == (int?)input.Enabled.Value);
        }

        protected override ISugarQueryable<RoleInfo> ApplyDefaultSorting(ISugarQueryable<RoleInfo> query)
        {
            return query.OrderBy((RoleInfo s) => s.CreateTime);
        }

        private async Task<List<RoleInfo>> GetByUser(int userID)
        {
            return await (from t in base.Client.Queryable((RoleInfo t, User_RoleInfo m) => t.Id == m.Role_ID && m.User_ID == userID)
                          select (t) into t
                          orderby t.CreateTime
                          select t).ToListAsync();
        }

        public async Task<List<RoleInfo>> GetRolesByOu(int ouID)
        {
            return await (from t in base.Client.Queryable((RoleInfo t, OU_RoleInfo m) => t.Id == m.Role_ID && m.Ou_ID == ouID)
                          select (t) into t
                          orderby t.CreateTime
                          select t).ToListAsync();
        }

        public async Task<List<RoleInfo>> GetRolesByFunction(string functionID)
        {
            return await (from t in base.Client.Queryable((RoleInfo t, Role_FunctionInfo m) => t.Id == m.Role_ID && m.Function_ID == functionID)
                          select (t) into t
                          orderby t.CreateTime
                          select t).ToListAsync();
        }

        public async Task<List<RoleInfo>> GetRolesByUser(int userID)
        {
            List<int> list = new List<int>();
            List<RoleInfo> rolesByUser = await GetByUser(userID);
            foreach (RoleInfo item in rolesByUser)
            {
                list.Add(item.Id);
            }
            foreach (OuInfo item2 in await _ouService.GetOUsByUser(userID))
            {
                foreach (RoleInfo item3 in await GetRolesByOu(item2.Id))
                {
                    if (!list.Contains(item3.Id))
                    {
                        rolesByUser.Add(item3);
                        list.Add(item3.Id);
                    }
                }
            }
            UserInfo userInfo = await _userService.GetAsync(userID);
            if (userInfo != null)
            {
                foreach (RoleInfo item4 in await GetRolesByOu(userInfo.Dept_ID.ToInt32()))
                {
                    if (!list.Contains(item4.Id))
                    {
                        rolesByUser.Add(item4);
                        list.Add(item4.Id);
                    }
                }
            }
            return rolesByUser;
        }

        public async Task<List<RoleInfo>> GetRolesByCompany(string companyId)
        {
            return (await GetAllAsync((RoleInfo s) => s.Company_ID == companyId && s.Deleted == (int?)0))?.Items.ToList();
        }

        public async Task<List<OuInfo>> GetMyTopGroup()
        {
            List<OuInfo> list = new List<OuInfo>();
            IApiUserSession userInfo = base.CurrentApiUser;
            if (userInfo != null)
            {
                if ((await GetRolesByUser(userInfo.Id.Value))?.Any((RoleInfo s) => s.Name == "超级管理员") ?? false)
                {
                    list = await _ouService.GetTopGroup();
                }
                else
                {
                    list.Add(await _ouService.GetAsync(userInfo.Company_ID.ToInt32()));
                }
            }
            return list;
        }

        public override async Task<bool> DeleteAsync(int id)
        {
            if (id == (await GetFirstAsync((RoleInfo s) => s.Name == "超级管理员"))?.Id)
            {
                throw new MyApiException("管理员角色 不能被删除！");
            }
            return await base.DeleteAsync(id);
        }

        public async Task<bool> AddFunction(string functionID, int roleID)
        {
            Role_FunctionInfo insertObj = new Role_FunctionInfo
            {
                Function_ID = functionID,
                Role_ID = roleID
            };
            return await base.Client.GetSimpleClient<Role_FunctionInfo>().InsertAsync(insertObj);
        }

        public async Task<bool> AddOU(int ouID, int roleID)
        {
            OU_RoleInfo insertObj = new OU_RoleInfo
            {
                Ou_ID = ouID,
                Role_ID = roleID
            };
            return await base.Client.GetSimpleClient<OU_RoleInfo>().InsertAsync(insertObj);
        }

        public async Task<bool> AddUser(int userID, int roleID)
        {
            User_RoleInfo insertObj = new User_RoleInfo
            {
                User_ID = userID,
                Role_ID = roleID
            };
            return await base.Client.GetSimpleClient<User_RoleInfo>().InsertAsync(insertObj);
        }

        public async Task<bool> UpdateRoleFunctions(UpdateRoleFunctionsDto dto)
        {
            SimpleClient<Role_FunctionInfo> biz = base.Client.GetSimpleClient<Role_FunctionInfo>();
            List<string> functions = dto.Functions;
            if (functions != null && functions.Count > 0)
            {
                ISugarQueryable<FunctionInfo, Role_FunctionInfo> sugarQueryable = base.Client.Queryable((FunctionInfo t, Role_FunctionInfo m) => t.Id == m.Function_ID && m.Role_ID == dto.RoleId && t.SystemType_ID == dto.SystemType && !dto.Functions.Contains(m.Function_ID));
                List<string> diffList = sugarQueryable.Select((FunctionInfo t, Role_FunctionInfo m) => t.Id).ToList();
                await biz.DeleteAsync((Role_FunctionInfo s) => diffList.Contains(s.Function_ID) && s.Role_ID == dto.RoleId);
                List<string> existList = (from s in biz.AsQueryable()
                                          where s.Role_ID == dto.RoleId
                                          select s.Function_ID).ToList();
                List<string> list = dto.Functions.FindAll((string s) => !existList.Contains(s));
                foreach (string item in list)
                {
                    await biz.InsertAsync(new Role_FunctionInfo
                    {
                        Function_ID = item,
                        Role_ID = dto.RoleId
                    });
                }
            }
            else
            {
                ISugarQueryable<FunctionInfo, Role_FunctionInfo> sugarQueryable2 = base.Client.Queryable((FunctionInfo t, Role_FunctionInfo m) => t.Id == m.Function_ID && m.Role_ID == dto.RoleId && t.SystemType_ID == dto.SystemType);
                List<string> diffList = sugarQueryable2.Select((FunctionInfo t, Role_FunctionInfo m) => t.Id).ToList();
                await biz.DeleteAsync((Role_FunctionInfo s) => diffList.Contains(s.Function_ID) && s.Role_ID == dto.RoleId);
            }
            return true;
        }

        public async Task<bool> UpdateRoleMenus(UpdateRoleMenusDto dto)
        {
            SimpleClient<Role_MenuInfo> biz = base.Client.GetSimpleClient<Role_MenuInfo>();
            List<string> menus = dto.Menus;
            if (menus != null && menus.Count > 0)
            {
                ISugarQueryable<MenuInfo, Role_MenuInfo> sugarQueryable = base.Client.Queryable((MenuInfo t, Role_MenuInfo m) => t.Id == m.Menu_ID && m.Role_ID == dto.RoleId && t.SystemType_ID == dto.SystemType && !dto.Menus.Contains(m.Menu_ID));
                List<string> diffList = sugarQueryable.Select((MenuInfo t, Role_MenuInfo m) => t.Id).ToList();
                await biz.DeleteAsync((Role_MenuInfo s) => diffList.Contains(s.Menu_ID) && s.Role_ID == dto.RoleId);
                List<string> existList = (from s in biz.AsQueryable()
                                          where s.Role_ID == dto.RoleId
                                          select s.Menu_ID).ToList();
                List<string> list = dto.Menus.FindAll((string s) => !existList.Contains(s));
                foreach (string item in list)
                {
                    await biz.InsertAsync(new Role_MenuInfo
                    {
                        Menu_ID = item,
                        Role_ID = dto.RoleId
                    });
                }
            }
            else
            {
                ISugarQueryable<MenuInfo, Role_MenuInfo> sugarQueryable2 = base.Client.Queryable((MenuInfo t, Role_MenuInfo m) => t.Id == m.Menu_ID && m.Role_ID == dto.RoleId && t.SystemType_ID == dto.SystemType);
                List<string> diffList = sugarQueryable2.Select((MenuInfo t, Role_MenuInfo m) => t.Id).ToList();
                await biz.DeleteAsync((Role_MenuInfo s) => diffList.Contains(s.Menu_ID) && s.Role_ID == dto.RoleId);
            }
            return true;
        }

        public async Task<bool> RemoveFunction(string functionID, int roleID)
        {
            return await base.Client.GetSimpleClient<Role_FunctionInfo>().DeleteAsync((Role_FunctionInfo s) => s.Function_ID == functionID && s.Role_ID == roleID);
        }

        public async Task<bool> RemoveOU(int ouID, int roleID)
        {
            return await base.Client.GetSimpleClient<OU_RoleInfo>().DeleteAsync((OU_RoleInfo s) => s.Ou_ID == ouID && s.Role_ID == roleID);
        }

        public async Task<bool> RemoveUser(int userID, int roleID)
        {
            RoleInfo roleInfo = await GetFirstAsync((RoleInfo s) => s.Name == "超级管理员");
            if (roleID == roleInfo?.Id && await base.Client.GetSimpleClient<UserInfo>().AsSugarClient().Queryable((UserInfo t, User_RoleInfo m) => t.Id == m.User_ID && m.Role_ID == roleID)
                .CountAsync() <= 1)
            {
                throw new MyApiException("管理员角色 至少需要包含一个用户！");
            }
            return await base.Client.GetSimpleClient<User_RoleInfo>().DeleteAsync((User_RoleInfo s) => s.User_ID == userID && s.Role_ID == roleID);
        }

        public async Task<bool> AddMenu(string menuID, int roleID)
        {
            Role_MenuInfo insertObj = new Role_MenuInfo
            {
                Menu_ID = menuID,
                Role_ID = roleID
            };
            return await base.Client.GetSimpleClient<Role_MenuInfo>().InsertAsync(insertObj);
        }

        public async Task<bool> RemoveMenu(string menuID, int roleID)
        {
            return await base.Client.GetSimpleClient<Role_MenuInfo>().DeleteAsync((Role_MenuInfo s) => s.Menu_ID == menuID && s.Role_ID == roleID);
        }

        public async Task<bool> SetDeletedFlag(int id, bool deleted = true)
        {
            bool result = false;
            int intDeleted = (deleted ? 1 : 0);
            RoleInfo roleInfo = await GetAsync(id);
            if (roleInfo != null)
            {
                roleInfo.Deleted = intDeleted;
                result = await UpdateAsync(roleInfo);
            }
            return result;
        }

        public async Task<bool> UserInRole(string userName, string roleName)
        {
            bool result = false;
            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(roleName))
            {
                UserInfo userInfo = await _userService.GetFirstAsync((UserInfo s) => s.Name == userName);
                if (userInfo != null)
                {
                    List<string> roleNames = roleName.ToDelimitedList<string>(",");
                    foreach (RoleInfo item in await GetRolesByUser(userInfo.Id))
                    {
                        if (roleNames.Contains(item.Name))
                        {
                            result = true;
                        }
                    }
                }
            }
            return result;
        }

        public async Task<bool> UserIsAdmin(string userName)
        {
            string roleName = string.Format("{0},{1}", "超级管理员", "系统管理员");
            return await UserInRole(userName, roleName);
        }

        public async Task<bool> OUInRole(int ouID, string roleName)
        {
            bool result = false;
            foreach (RoleInfo item in await GetRolesByOu(ouID))
            {
                if (item.Name == roleName)
                {
                    result = true;
                    break;
                }
            }
            return result;
        }

        public async Task<List<TreeNodeItem>> GetRoleCategories()
        {
            List<TreeNodeItem> list = new List<TreeNodeItem>();
            string[] memberNames = EnumHelper.GetMemberNames<RoleCategoryEnum>();
            foreach (string text in memberNames)
            {
                list.Add(new TreeNodeItem(text));
            }
            return await Task.FromResult(list);
        }
    }

}
